/* Copyright  2009
   @Author
   Richard Changde Yin            e-mail yinchangde@hotmail.com

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/**
 * @filename: mfieldList.cc
 */
#include<server_includes.h>
#include<table.h>
#include<index.h>
#include<catalogtables.h>
#include<lock.h>
#include<debug.h>

using namespace BackEnd;

//does not check for duplicates
BackEnd::DbRetVal M_FieldList::append(m_field_def* fDef)
{
    M_FieldNode*  newNode = new M_FieldNode(fDef);
    //If this is the first node, set it as head
    if (!head)
    { head = newNode;
    }else{
     M_FieldNode *iter = head;
     while (iter->next) iter = iter->next;
     iter->next = newNode;
    }
    _size ++ ;
    return BackEnd::OK;
}


BackEnd::DbRetVal M_FieldList::remove(const char* fldName)
{
    if (!head)
    {
      return BackEnd::ER_NotExists;
    }
    bool isFound = false ;
    M_FieldNode *iter = head, *prev = head;
    while (iter->next != NULL)
    {
        if (0 == strcmp(iter->fldDef->fldName_, fldName))
        {
            prev->next = iter->next;
            delete iter;
            _size --   ;
            isFound = true ;
        }
        prev = iter;
        iter = iter->next;
    }
    if( iter == head) // there is only one node in the list
    {
        if (0 == strcmp(iter->fldDef->fldName_, fldName))
        {
            delete head;
            head = NULL;
            _size --   ;
            return BackEnd::OK;
        }

    }
    if( prev == head) // there are only two node in the list
    {
        if (0 == strcmp(iter->fldDef->fldName_, fldName))
        {
            head->next = NULL;
            delete iter;
            _size --   ;
            return BackEnd::OK;
        }
    }

    if (!isFound) {
       //printError(BackEnd::ER_NotFound, "There are no elements in the list");
       return BackEnd::ER_NotFound;
    }else
    {
       return BackEnd::OK;
    }
}

DbRetVal M_FieldList::removeAll()
{
    if (head) {
     M_FieldNode *iter = head;
     M_FieldNode *next = head;
     while (iter->next)
     {
        next = iter->next;
        delete iter;
        iter = next;
     }
     delete iter;  //deleting the last element
    }
    head  = 0;
    _size = 0 ;
    return OK;
}
/*************************************************************

    @return -1->if val is passed NULL
    @return -2->if fld is not present

**************************************************************/
BackEnd::DbRetVal M_FieldList::updateBindVal(const char *fldName, void *val )
{
    if (NULL == val)
    {
        //printError(BackEnd::ER_BadArg, "Value passed is NULL");
        return BackEnd::ER_BadArg;
    }
    M_FieldNode *iter = head;
    while(NULL != iter)
    {
        if (strcmp(iter->fldDef->fldName_, fldName) == 0)
        {
            iter->fldDef->bindVal_ = val;
            return BackEnd::OK;
        }
        iter = iter ->next;
    }
    //printError(BackEnd::ER_NotFound, "Field not present in the list");
    return BackEnd::ER_NotFound;
}
void *M_FieldList::getBindField(const char *fldName)
{
    M_FieldNode *iter = head;
     while(NULL != iter)
    {
      if (strcmp(iter->fldDef->fldName_, fldName) == 0)
      {
       return  iter->fldDef->bindVal_;
      }
      iter = iter ->next;
    }
    //printError(BackEnd::ER_NotFound, "Field not present in the list");
    return NULL;
}
BackEnd::DbRetVal M_FieldList::getFieldInfo(const char *fldName,
                                            m_field_def *&info)
{

    M_FieldNode *iter = head;
    if ('*' == fldName[0])
    {
        info = iter->fldDef ;
        return BackEnd::OK;

    }
    while(iter != NULL)
    {
        if (0 == memcmp(iter->fldDef->fldName_, fldName,iter->fldDef->fldNameRealLen))
        {
            info = iter->fldDef ;
            return BackEnd::OK;
        }
        iter = iter ->next;
    }
    return BackEnd::ER_NotFound;
}

int16_t M_FieldList::getFieldOffset(const char *fldName)
{
    M_FieldNode *iter = head;
    int16_t offset= 0;
    while(iter != NULL)
    {
        if (0 == strcmp(iter->fldDef->fldName_, fldName))
        {
            return offset;
        }
        offset = offset + OS::align(iter->fldDef->length_);
        iter = iter ->next;
        }
        return -1;
}
int16_t M_FieldList::getFieldOffset(int fldpos)
{
    if (fldpos < 1) return -1;
    M_FieldNode *iter = head;
    int offset = 0;
    int counter =0;
    while(iter != NULL)
    {
        if (counter == fldpos -1)
        {
            return offset;
        }
        offset = offset + OS::align(iter->fldDef->length_);
        iter = iter ->next;
        counter++;
    }
    return -1;
}

//Returns position of field in the list
//Count starting from 1
//-1 if field not found in the list
int16_t M_FieldList::getFieldPosition(const char *fldName)
{
    int position = 1;
    M_FieldNode *iter = head;
    while(iter != NULL)
    {
        if (0 == strcmp(iter->fldDef->fldName_, fldName))
            return position;
        position++;
        iter  = iter->next;
    }

    return -1;
}

uint32_t M_FieldList::getTupleSize()
{
    M_FieldNode *iter = head;
    int offset = 0;
    while(iter != NULL)
    {
        offset = offset + OS::align(iter->fldDef->length_);
        iter = iter ->next;
    }
    return offset;
}



enum_field_types M_FieldList::getFieldType(const char *fldName)
{
    M_FieldNode *iter = head;
    while(iter != NULL)
    {
        if (0 == strcmp(iter->fldDef->fldName_, fldName))
        {
            return iter->fldDef->type_;
        }
        iter = iter ->next;
        }
    return COLLAPSAR_TYPE_UNKNOWN;
}

//-1->if field not present in list
size_t M_FieldList::getFieldLength(const char *fldName)
{
    M_FieldNode *iter = head;
    while(iter != NULL)
    {
        if (0 == strcmp(iter->fldDef->fldName_, fldName))
        {
            return iter->fldDef->length_;
        }
        iter = iter ->next;
    }
    return -1;
}
